#include<stdio.h>
#include<assert.h>
#include"absyn.h"
#include"util.h"

struct table* typetable = NULL;
struct table* valuetable = NULL;

struct CM_type* newtype(int k, struct symbol* s)
{
	struct CM_type* ptr = (struct CM_type*)sec_malloc(sizeof(struct CM_type));
	ptr->kind = k;
	ptr->type = s;

	return ptr;
}

struct CM_vardecl* newvardecl(struct CM_type* ty, struct symbol* sym)
{
	struct CM_vardecl* ptr = (struct CM_vardecl*)sec_malloc(sizeof(struct CM_vardecl));
	ptr->type = ty;
	ptr->u.sym = sym;

	return ptr;
}

struct CM_vardecl* newarrdecl(struct CM_type* ty, struct symbol* sym, struct CM_exp* size)
{
	struct CM_vardecl* ptr = (struct CM_vardecl*)sec_malloc(sizeof(struct CM_vardecl));
	ptr->type = ty;
	ptr->type->kind = cm_ty_arr;
	ptr->u.arr = (struct ArrDecl*)sec_malloc(sizeof(struct ArrDecl));
	ptr->u.arr->sym = sym;
	ptr->u.arr->size = size;

	return ptr;
}

struct CM_vardeclist* newvardeclist(struct CM_vardecl* var, struct CM_vardeclist* next)
{
	struct CM_vardeclist* ptr = (struct CM_vardeclist*)sec_malloc(sizeof(struct CM_vardeclist));
	ptr->stfield = var;
	ptr->next = next;

	return ptr;
}

struct CM_typedecl* newtypedecl(struct symbol* sym, struct CM_vardeclist* list)
{
	struct CM_typedecl* ptr = (struct CM_typedecl*)sec_malloc(sizeof(struct CM_typedecl));
	ptr->sym = sym;
	ptr->list = list;

	return ptr;
}

struct CM_decl* newdecl(int k, void* binding)
{
	struct CM_decl* ptr = (struct CM_decl*)sec_malloc(sizeof(struct CM_decl));
	ptr->kind = k;
	switch(k)
	{
		case cm_typedecl:
			ptr->u.st = (struct CM_typedecl*)binding;
			break;
		case cm_vardecl:
			ptr->u.type = (struct CM_vardecl*)binding;
			break;
		case cm_fundecl:
			ptr->u.fun = (struct CM_fundecl*)binding;
			break;
		default:
			printf("unexpected type\n");
	}

	return ptr;
}

struct CM_exp* newexp(int k, void* left, void* right)
{
	struct CM_exp* ptr = (struct CM_exp*)sec_malloc(sizeof(struct CM_exp));
	ptr->kind = k;
	switch(k)
	{
		case cm_const_int:
		case cm_const_float:
		case cm_const_char:
			ptr->u.id = (struct symbol*)left;
			break;
		case cm_parent:
		case cm_plus:
		case cm_minus:
		case cm_mul:
		case cm_div:
		case cmp_Less:
        case cmp_LE:
        case cmp_Equal:
        case cmp_Great:
        case cmp_GE:
        case cmp_NE:
			ptr->u.kid = (struct CM_exp_st*)sec_malloc(sizeof(struct CM_exp_st));
			ptr->u.kid->left = (struct CM_exp*)left;
			ptr->u.kid->right = (struct CM_exp*)right;
			break;
		case cm_var:
			ptr->u.var = (struct CM_var*)left;
			break;
		case cm_funcall:
			ptr->u.fun = (struct CM_fun_call*)sec_malloc(sizeof(struct CM_fun_call));
			ptr->u.fun->funName = (struct symbol*)left;
			ptr->u.fun->paramlist = (struct CM_varlist*)right;
			break;
		default:
			printf("unexpected type\n");
	}

	return ptr;
}

struct CM_stmt* newstmt(int k, void*binding)
{
	struct CM_stmt* ptr = (struct CM_stmt*)sec_malloc(sizeof(struct CM_stmt));
	ptr->kind = k;
	switch(k)
	{
		case cm_exp:
			ptr->u.exp = (struct CM_exp*)binding;
			break;
		case cm_blockstmt:
			ptr->u.sl = (struct CM_stmtlist*)binding;
			break;
		case cm_decl:
			ptr->u.de = (struct CM_decl*)binding;
			break;
		case cm_assign:
			ptr->u.as = (struct CM_assign*)binding;
			break;
		case cm_if:
			ptr->u.i = (struct CM_if*)binding;
			break;
		case cm_for:
			ptr->u.f = (struct CM_for*)binding;
			break;
		case cm_while:
			ptr->u.w = (struct CM_while*)binding;
			break;
		case cm_return:
			ptr->u.exp = (struct CM_exp*)binding;
			break;
		default:
			printf("unexpected type\n");
	}

	return ptr;
}

struct CM_var* newvar(int k, struct symbol* sym, void* binding)
{
	struct CM_var* ptr = (struct CM_var*)sec_malloc(sizeof(struct CM_var));
	ptr->kind = k;
	switch(k){
		case var_abs_id:
			ptr->u.sym = sym;
			break;
		case var_abs_array:
			ptr->u.arr = (struct CM_arr_get*)sec_malloc(sizeof(struct CM_arr_get));
			ptr->u.arr->id = sym;
			ptr->u.arr->index = (struct CM_exp*)binding;
			break;
		case var_abs_struct:
			ptr->u.stu = (struct CM_struct_get*)sec_malloc(sizeof(struct CM_struct_get));
			ptr->u.stu->sym = sym;
			ptr->u.stu->field = (struct symbol*)binding;
			break;
		default:
			printf("not support now.\n");
	}
	return ptr;
}

struct CM_stmtlist* newstmtlist(struct CM_stmt* stmt, struct CM_stmtlist* next)
{
	struct CM_stmtlist* ptr = (struct CM_stmtlist*)sec_malloc(sizeof(struct CM_stmtlist));
	ptr->stm = stmt;
	ptr->next = next;

	return ptr;
}

struct CM_assign* newassign(struct CM_var* var, struct CM_exp* exp)
{
	struct CM_assign* ptr = (struct CM_assign*)sec_malloc(sizeof(struct CM_assign));
	ptr->var = var;
	ptr->exp = exp;

	return ptr;
}

struct CM_if* newif(struct CM_exp* cond, struct CM_stmt* match, struct CM_stmt* unmatch)
{
	struct CM_if* ptr = (struct CM_if*)sec_malloc(sizeof(struct CM_if));
	ptr->cond = cond;
	ptr->match = match;
	ptr->unmatch = unmatch;

	return ptr;
}
struct CM_while* newwhile(struct CM_exp* cond, struct CM_stmt* match)
{
	struct CM_while* ptr = (struct CM_while*)sec_malloc(sizeof(struct CM_while));
	ptr->cond = cond;
	ptr->match = match;

	return ptr;
}
struct CM_for* newfor(struct CM_assign* init, struct CM_exp* cond, struct CM_assign* after, struct CM_stmt* match)
{
	struct CM_for* ptr = (struct CM_for*)sec_malloc(sizeof(struct CM_for));
	ptr->cond = cond;
	ptr->match = match;
	ptr->init = init;
	ptr->after = after;

	return ptr;
}

struct CM_fundecl* newfundecl(struct CM_type* type, struct symbol* funName, struct CM_vardeclist* paramlist, struct CM_stmtlist* stmt)
{
	struct CM_fundecl* ptr = (struct CM_fundecl*)sec_malloc(sizeof(struct CM_fundecl));
	ptr->type = type;
	ptr->funName = funName;
	ptr->paramlist = paramlist;
	ptr->stmt = stmt;
	return ptr;
}
struct CM_varlist* newvarlist(struct CM_exp* exp, struct CM_varlist* next)
{
	struct CM_varlist* ptr = (struct CM_varlist*)sec_malloc(sizeof(struct CM_varlist));
	ptr->exp = exp;
	ptr->next = next;
	return ptr;
}

int getCmpOp(int i)
{
	switch(i){
		case 0:
			return cmp_Less;
		case 1:
			return cmp_LE;
		case 2:
			return cmp_Equal;
		case 3:
			return cmp_Great;
		case 4:
			return cmp_GE;
		case 5:
			return cmp_NE;
		default:
			return cmp_Equal;
	}
}